package org.haptimap;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.location.Location;
import android.location.LocationListener;
import android.opengl.GLSurfaceView;
import android.os.Bundle;

public class HaptiMap
{
    static
    {
        /* Load the native toolkit library once and once only, when this
         * class is first instantiated. */
    	System.loadLibrary("haptimap");
    }

    /* Constructor should be passed an instance of an Android context
     * (the Toolkit Service will do fine) which can then be stored and 
     * accessed by any JNI function calls that need an Android context. */
    public HaptiMap(Context ctx)
    {
        context = ctx;
    }

    /** Pointer to tookit internal state is stored here by JNI wrapper functions */
    private long hm;
    /** Reference to Android context stored here by constructor for use by JNI */
    private Context context;


    /* Defines and Enums used by toolkit API */

    /* Toolkit function return codes */
    public static final int SUCCESS = 1;
    public static final int FAILURE = 0;

    /** 
     * Attributes of user-facing logical devices (i.e. sensors, haptic output 
     * effectors etc.)
     */
    public static enum ATTRIBUTE
    {
        SENSOR_TYPE,          /**< integer: enum SENSOR_TYPE */
        ACTIVE,               /**< integer: 1 = active and receiving/sending updates from/to 
                                  *   underlying physical hardware device; 0 = inactive (default 
                                  *   state as created). The active state for a sensor device can 
                                  *   be set and unset using hmSensorInitialise() and 
                                  *   hmSensorUninitialise() respectively. */
        MIN_VALUE,            /**< variable type: minimum value for this logical device */
        MAX_VALUE,            /**< variable type: maximum value for this logical device */
        LAST_UPDATE_TIME,     /**< integer: seconds since Unix epoch */
        POWER_LEVEL,          /**< integer, range 0-100: power/battery level of underlying 
                                  *   hardware device */
        DEVICE_TYPE,          /**< integer: enum DEVICE_TYPE */
        DEVICE_ID,            /**< integer: unique device ID of the underlying hardware 
                                  *   device */
        DEVICE_RELATIVE_ID,   /**< integer: ID of this logical device relative to the 
                                  *   hardware device (0 if the hardware device only supports
                                  *   one of this type of logical device) */
        DEVICE_RELATIVE_NAME, /**< string: name of this logical device relative to the
                                  *   hardware device, e.g. "X" for the x-axis accelerometer
                                  *   from a device with a tri-axial accelerometer */
        LOCATION_ACCURACY,     /**< integer: accuracy value for a location sensor, 
                                  *   independent of toolkit co-ordinate system. Approximate 
                                  *   value in millimeters */
        LOCATION_SPEED,       /**< integer: speed of the device in m/s */
        LOCATION_BEARING      /**< integer: the direction of travel in degrees East of true North */
    };

    /**
     * User-facing, logically abstracted sensor devices
     */
    public static enum SENSOR_TYPE
    {
        ACCELEROMETER,   /**< Accelerometer: single integer representing milli-g,
                                    *   i.e. thousandths of the acceleration due to gravity */
        TEMPERATURE,     /**< Temperature sensor: single integer representing 
                                    *   one tenth of one degree Celsius */
        HAPTIC_POSITION, /**< Haptic Position sensor: array of 6 integers 
                                    *   representing:
                                    *     - Elements 0-2: x, y and z co-ordinates of the
                                    *       location of the haptic effector within the 
                                    *       reference frame of the haptic device. 
                                    *     - Elements 3-5: Rotation of the haptic end effector 
                                    *       about the x, y and z-axes respectively, relative
                                    *       to the reference frame of the end effector.
                                    *       Angles are given in tenths of a degree, positive
                                    *       anticlockwise from right, i.e. a maximum range
                                    *       of +/- 1800.
                                    *       
                                    *   The definition and range of the reference frame of the
                                    *   device and end effector depends on the underlying haptic 
                                    *   hardware being used. The range can be determined by 
                                    *   calling hmSensorGetAttribute() with the HaptiMap.ATTRIBUTE.MIN_VALUE 
                                    *   and HaptiMap.ATTRIBUTE.MAX_VALUE attributes. */
        PRESSURE,
        PHYSIOLOGICAL,
        SWITCH,          /**< Switch: single integer; 1 = on, 0 = off */
        GYROSCOPE,
        LIGHT,
        COMPASS,
        PROXIMITY,
        MAGNETIC_FIELD
    };

    /** 
     * Events that may be handled by a callback
     */
    public static enum EVENT_TYPE
    {
        UPDATE,    /**< sensor-type device has had its value updated */
        DISCONNECT, /**< underlying hardware device has disconnected */
        RENDER    /**< device needs callback function to render haptic surface    */
    };

    /** Capabilities of geographical data plugins */
    public static enum PLUGIN_CAPABILITY
    {
        COORDINATE_TRANSFORMATION, /**< plugin that provides co-ordinate transformation,
                                    * i.e. defines a co-ordinate system that can be used 
                                    * as the toolkit internal system */
        DATA_SOURCE /**< plugin that provides a source of geographical data for any area */
    };

    /** Internal geometry storage types */
    public static enum GEOMETRY_TYPE
    {
        POINT,     /**< single point; may be 2-D or 3-D */
        LINESTRING /**< string of points; may be 2-D or 3-D and may be unterminated
                    *   (i.e. a linestring) or have an implicit last point at the 
                    *   same location as the first (i.e. a polygon). */
    };

    /** Attribute types for geographical data storage */
    public static enum ATTRIBUTE_TYPE
    {
        SINGLE,   /**< single integer */
        MULTIPLE, /**< array of integers */
        STRING    /**< null-terminated string */
    };

    /** Callback interface used with toolkit functions that require a callback
     *  to be defined. The user should define a class that "implements" this 
     *  interface (and store any local context information that they need in private
     *  member variables). The toolkit will call the callback() method when necessary. */
    public static interface HaptiMapCallbackType
    {
        public void callback();
    }


    /* Public methods, mapping in general to toolkit public C API */

    /* Initialisation */

    /**
     * Initialise the HaptiMap toolkit.
     * 
     * Load any installed components, read any configuration data and determine 
     * the hardware environment. Must be called before any other functions.
     */
    public native int Initialise();
    /**
     * Uninitialise the HaptiMap toolkit.
     * 
     * Terminate communications with any hardware devices and release all 
     * resources used.
     */
    public native int Uninitialise();

    /* Data Transfer Control API */
    /**
     * Inquire how many plugins with the given capability are currently loaded
     * 
     * @param cap   Capability: supported values are:<br>
     *              <ul>
     *              <li>HaptiMap.PLUGIN_CAPABILITY.COORDINATE_TRANSFORMATION</li>
     *              <li>HaptiMap.PLUGIN_CAPABILITY.DATA_SOURCE</li>
     *              </ul>
     * @param count Single-element integer array into which the number of available 
     *              plugins with the specified capability will be placed
     */
    public native int GeoPluginInquire(PLUGIN_CAPABILITY cap, int[] count);
    /**
     * Get the unique plugin ID of the nth plugin with a given capability
     * 
     * @param cap   Capability: supported values are:<br>
     *              <ul>
     *              <li>HaptiMap.PLUGIN_CAPABILITY.COORDINATE_TRANSFORMATION</li>
     *              <li>HaptiMap.PLUGIN_CAPABILITY.DATA_SOURCE</li>
     *              </ul>
     * @param n     Select the nth plugin with this capability
     * @param id    Single-element integer array into which the unique ID
     *              will be placed
     * 
     * @return HaptiMap.FAILURE if an invalid plugin number was specified, otherwise HaptiMap.SUCCESS
     */
    public native int GeoPluginGetId(PLUGIN_CAPABILITY cap, int n, int[] id);
    /**
     * Get the human-readable name of a given plugin
     * 
     * @param id
     *   Unique plugin ID
     * @param name
     *   <code>java.lang.StringBuilder</code> object, which the plugin name 
     *   will be appended to.
     * 
     * @return HaptiMap.FAILURE if an invalid plugin ID was specified, otherwise 
     *         HaptiMap.SUCCESS
     */
    public native int GeoPluginGetName(int id, StringBuilder name);

    /**
     * Determine the ID of the lead plugin for co-ordinate transformations
     * 
     * @param id Single-element integer array into which the unique plugin 
     *           ID of the current lead plugin will be placed.
     */
    public native int GeoGetLeadPlugin(int[] id);
    /**
     * Set the lead plugin to be used for co-ordinate transformations
     * 
     * Before calling this function, the toolkit internal geographical data storage
     * must be erased (by calling GeoEraseStorage()), since the lead plugin 
     * defines the co-ordinate system used.
     * 
     * @param id Plugin ID of the plugin to be set as lead
     * 
     * @return HaptiMap.SUCCESS if either the specified plugin already is the lead
     *         plugin, or it was successfully set as the lead plugin. HaptiMap.FAILURE if
     *         an invalid plugin ID was specified or cached geographical data storage
     *         files exist that have been initialised using a different lead plugin.
     */
    public native int GeoSetLeadPlugin(int id);

    /**
     * Determine whether a given plugin provides geographic data coverage of
     * a particular point
     * 
     * If the plugin does not provide a data source, the function will simply indicate
     * that it does not provide coverage for the point.
     * 
     * @param id      Plugin ID of the plugin being queried
     * @param point   Two-element integer array containing x,y toolkit co-ordinates of the point
     * @param covered Single-element integer array into which a value of 1 will be
     *                placed if the plugin provides coverage of the point, and 0 if not.
     * 
     * @return HaptiMap.SUCCESS if the coverage of the point is successfully determined.
     *         HaptiMap.FAILURE if an invalid plugin ID was specified, there was an error
     *         querying the plugin for its coverage bounding box, or there was an
     *         error converting points to and from toolkit co-ordinates.
     */
    public native int GeoPluginCoversPoint(int id, int[] point, int[] covered);
    /**
     * Determine whether a given plugin provides geographic data coverage of
     * a particular area defined by a rectangular bounding box
     * 
     * If the plugin does not provide a data source, the function will simply indicate
     * that it does not provide coverage for the area.
     * 
     * @param id      Plugin ID of the plugin being queried
     * @param bbox    4-element integer array containing x,y toolkit co-ordinates of the lower
     *                left and upper right corners of the bounding box respectively
     * @param covered Single-element integer array into which a value of 1 will be
     *                placed if the plugin provides coverage of the area, and 0 if not.
     * 
     * @return HaptiMap.SUCCESS if the coverage of the area is successfully determined.
     *         HaptiMap.FAILURE if an invalid plugin ID was specified, there was an error
     *         querying the plugin for its coverage bounding box, or there was an
     *         error converting points to and from toolkit co-ordinates.
     */
    public native int GeoPluginCoversArea(int id, int[] bbox, int[] covered);
    /**
     * Determine the toolkit feature types supported/provided by a given plugin
     * 
     * When the function is called, num_features[0] should contain the size of the output
     * array feature_list, and on return it will contain the number of supported features 
     * available. The function can thus initially be called with zero for this value, in 
     * order to determine an appropriate size for the feature_list array on subsequent calls.
     * 
     * @param id
     *   Plugin ID of the plugin to be queried
     * @param feature_list
     *   Integer array into which the feature type codes of supported
     *   features will be placed. Must be at least of the size specified by num_features[0].
     * @param num_features
     *   Single-element integer array containing the maximum size of the provided array feature_list. 
     *   On return this will contain the number of features that were available; if the
     *   specified maximum size was less than this then not all feature type codes will 
     *   have been copied to feature_list.
     * 
     * @return
     *   HaptiMap.SUCCESS if the plugin was successfully queried, irrespective of whether the 
     *   number of feature type codes that was copied to the feature_list array was 
     *   limited by the value of num_features[0] passed to the function. HaptiMap.FAILURE if an 
     *   invalid plugin ID was specified.
     */
    public native int GeoPluginFeatureTypes(int id, int[] feature_list, int[] num_features);
    /**
     * Enable a particular feature type for a given plugin, so that when data is
     * loaded using the plugin, this feature type will be among those retrieved.
     * 
     * @param id
     *   Plugin ID of the plugin for which the feature is to be enabled
     * @param feature_id
     *   Feature type code of the feature to be enabled
     * 
     * @return
     *   HaptiMap.SUCCESS if the feature was successfully enabled. HaptiMap.FAILURE if an invalid
     *   plugin ID or feature type code were specified.
     */
    public native int GeoPluginEnableFeature(int id, int feature_id);
    /**
     * Disable a particular feature type for a given plugin, so that the next
     * time data is loaded using the plugin, this feature type will not be 
     * among those newly retrieved.
     * 
     * @param id
     *   Plugin ID of the plugin for which the feature is to be disabled
     * @param feature_id
     *   Feature type code of the feature to be disabled
     * 
     * @return
     *   HaptiMap.SUCCESS if the feature was successfully disabled. HaptiMap.FAILURE if an invalid
     *   plugin ID or feature type code were specified.
     */
    public native int GeoPluginDisableFeature(int id, int feature_id);
    /**
     * Load geographic data from the given plugin within the area specified
     * by the given rectangular bounding box.
     *
     * Only those feature types that have been previously enabled with a call to 
     * hm_geo_plugin_feature_enable() will be loaded.
     * 
     * @param id
     *   Plugin ID of the plugin from which data is to be loaded
     * @param bbox
     *  4-element integer array containing x,y toolkit co-ordinates of the lower
     *  left and upper right corners of the bounding box respectively
     * 
     * @return
     *   HaptiMap.SUCCESS if data was successfully loaded, otherwise HaptiMap.FAILURE
     */
    public native int GeoPluginLoadBBox(int id, int[] bbox);

    /**
     * Flush current state of toolkit internal geographical data storage to disk
     * 
     * Although the individual elements of the geographical data (co-ordinates, attribute 
     * values etc.) are held in memory-mapped files and thus automatically always kept
     * in-sync between memory and disk-based storage, the configuration file describing
     * the persistent state of this cached storage is normally only written to disk when
     * the toolkit is shut down. This is perfectly adequate for most normal usage of the
     * toolkit, but for applications that may be unexpectedly or abnormally terminated it
     * may be additionally advantageous to flush the persistent state to disk during 
     * normal operation of the toolkit, e.g. immediately after a large download of data
     * from a plugin. This guards against the contents of the internal storage being lost
     * if the toolkit is abnormally terminated.
     * 
     * @return 
     *   HaptiMap.SUCCESS if storage state successfully saved to disk, otherwise HaptiMap.FAILURE.
     */
    public native int GeoFlushStorage();
    /**
     * Erase geodata storage and truncate memory-mapped files to zero length
     * 
     * @return
     *   HaptiMap.SUCCESS if the storage was successfully erased; HaptiMap.FAILURE if there was a
     *   problem resizing the memory-mapped files.
     */
    public native int GeoEraseStorage();

    /* Geographical Data Storage API */

    public native int GeoPointGet(int id, int[] x, int[] y, int[] z, int[] is_3d);
    public native int GeoLineStringDescribe(int id, int[] num_pts, int[] is_3d, int[] is_polygon);
    public native int GeoLineStringGet(int id, int[] x, int[] y, int[] z);
    public native int GeoLineStringGetPoint(int id, int[] x, int[] y, int[] z, int idx);

    public native int GeoAttributeGetId(GEOMETRY_TYPE gtype, int feat_id, int n, int[] att_id);
    public native int GeoAttributeDescribe(int att_id, int[] code, int[] att_type);
    public native int GeoAttributeGet(int att_id, int[] val);
    public native int GeoAttributeGetMultiple(int att_id, int[] vals, int[] num_vals);
    public native int GeoAttributeGetString(int att_id, StringBuilder val);

    public native int GeoListAll(GEOMETRY_TYPE gtype, int[] list, int[] num); 

    /* Location Sensor API */
    /**
     * Determine the number of location sensors present and
     * available to the HaptiMap toolkit
     * 
     * @param count Single-element integer array into which the number
     *              of location sensors found will be placed
     * 
     * @return HaptiMap.SUCCESS (even if no location sensors were found).
     */
    public native int LocationSensorInquire(int[] count);
    /**
     * Get the unique ID of the nth location sensor
     * 
     * @param n           Select the nth sensor
     * @param id          Single-element integer array into which the unique ID
     *                    will be placed
     * 
     * @return HaptiMap.SUCCESS if sensor ID correctly found, HaptiMap.FAILURE if
     *         n is out of range.
     */
    public native int LocationSensorGetId(int n, int[] id);
    /**
     * Get the value of a certain attribute for a particular location
    * sensor as an integer
     * 
     * @param id  
     *   Unique ID of the location sensor to be queried
     * @param att
     *   Attribute to be queried: supported attributes are:<br>
     *   <ul>
     *   <li>HaptiMap.ATTRIBUTE.ACTIVE</li>
     *   <li>HaptiMap.ATTRIBUTE.POWER_LEVEL</li>
     *   <li>HaptiMap.ATTRIBUTE.DEVICE_TYPE</li>
     *   <li>HaptiMap.ATTRIBUTE.DEVICE_ID</li>
     *   <li>HaptiMap.ATTRIBUTE.DEVICE_RELATIVE_ID</li>
     *   <li>HaptiMap.ATTRIBUTE.LOCATION_ACCURACY</li>
     *   </ul>
     * @param val 
     *   Single-element integer array into which the attribute value will be placed
     * 
     * @return HaptiMap.SUCCESS if attribute successfully queried, HaptiMap.FAILURE if an
     *         invalid location sensor ID or attribute was specified, or the 
     *         attribute does not support representation as a single integer.
     */
    public native int LocationSensorGetAttribute(int id, ATTRIBUTE att, int[] val);
    /**
     * Get the value of a certain attribute for a particular 
     * location sensor as a string
     * 
     * @param id  
     *   Unique ID of the location sensor to be queried
     * @param att
     *   Attribute to be queried: supported attributes are HaptiMap.ATTRIBUTE.DEVICE_RELATIVE_NAME only.
     * @param val 
     *   <code>java.lang.StringBuilder</code> object, which the string will be appended to.
     * 
     * @return HaptiMap.SUCCESS if attribute successfully queried, HaptiMap.FAILURE if an
     *         invalid location sensor ID or attribute was specified, or the 
     *         attribute does not support representation as a string.
     */
    public native int LocationSensorGetAttributeString(int id, ATTRIBUTE att, StringBuilder val);

    /**
     * Activate a location sensor so that its value and attributes are 
     * continuously updated by the toolkit
     * 
     * Any underlying hardware is enabled appropriately.
     * 
     * @param id Unique ID of the sensor to be activated
     * 
     * @return HaptiMap.SUCCESS if sensor successfully activated, HaptiMap.FAILURE if an
     *         invalid sensor ID is specified, if the sensor is already
     *         activated, or there was an internal error.
     */
    public native int LocationSensorInitialise(int id);
    /**
     * Deactivate a location sensor and stop it being updated by the toolkit
     * 
     * Turns off hardware support for the sensor if relevant.
     * 
     * @param id Unique ID of the sensor to be deactivated
     * 
     * @return HaptiMap.SUCCESS if sensor successfully deactivated, HaptiMap.FAILURE if an
     *         invalid sensor ID is specified, if the sensor is not active,
     *         or there was an internal error.
     */
    public native int LocationSensorUninitialise(int id);
    /**
     * Associate a callback with a particular location sensor and event
     * 
     * @param id 
     *   Unique ID of the sensor with which the callback is to be associated
     * @param event
     *   Event type, an occurence of which will trigger the callback: supported events
     *   are HaptiMap.EVENT_TYPE.UPDATE and HaptiMap.EVENT_TYPE.DISCONNECT.
     * @param cb_interface
     *   Object that implements the <code>org.haptimap.HaptiMap.HaptiMapCallbackType</code>
     *   interface. This object's <code>callback</code> method will be called if and
     *   when the callback is triggered.
     * 
     * @return 
     *   HaptiMap.SUCCESS if the callback was successfully prepared and associated
     *   with the sensor and event. HaptiMap.FAILURE if an invalid sensor ID or
     *   event type was specified, or the sensor already has a callback
     *   defined for this event.
     */
    public native int LocationSensorDefineCallback(int id, EVENT_TYPE event, HaptiMapCallbackType cb_interface);
    /**
     * Cancel the callback function associated with a particular location
     *        sensor and event.
     * 
     * Once this function has returned, the previously specified callback will
     * no longer be called even if the event occurs.
     * 
     * @param id
     *   Unique ID of the sensor for which the callback is to be canceled
     * @param event
     *   The event type for which the callback is to be cancelled: supported 
     *   events are HaptiMap.EVENT_TYPE.UPDATE and HaptiMap.EVENT_TYPE.DISCONNECT.
     * 
     * @return
     *   HaptiMap.SUCCESS if the callback was successfully disassociated. HaptiMap.FAILURE
     *   if an invalid sensor ID or event type was specified, or the sensor
     *   did not have a callback defined for this event.
     */
    public native int LocationSensorCancelCallback(int id, EVENT_TYPE event);
    /**
     * Retrieve the current location in integer toolkit co-ordinates
     * 
     * @param id
     *   Unique ID of the location sensor to query
     * @param location
     *   Three-element integer array, into which the retrieved location 
     *   co-ordinates will be stored in the order (x, y, z). x corresponds to 
     *   east and y to north. z is a height value along an axis approximately 
     *   perpendicular to the xy-plane, increasing in a right-handed direction.
     * @param is_3d
     *   Single-element integer array, into which a value of 1 will be stored if 
     *   the location retrieved has a third dimension (i.e. z/height value) and 0 
     *   if not.
     * 
     * @return
     *   HaptiMap.SUCCESS if a valid current location was successfully stored in the
     *   array location. HaptiMap.FAILURE if an invalid sensor ID was given, if the
     *   sensor was currently inactive, or if the sensor cannot currently
     *   offer a valid accurate location reading.
     */
    public native int LocationSensorGetLocation(int id, int[] location, int[] is_3d);
    /**
     * Retrieve the current location in GPS co-ordinates, i.e. WGS84
     *        latitude, longitude and ellipsoidal height, if possible
     * 
     * @param id
     *   Unique ID of the location sensor to query
     * @param location
     *   Three-element array of double-precision floating point values, into which 
     *   the retrieved location will be stored in the order (latitude, longitude,
     *   ellipsoidal height).
     * @param is_3d
     *   Single-element integer array, into which a value of 1 will be stored if the 
     *   location retrieved has a third dimension (i.e. ellipsoidal height) and 0 if 
     *   not.
     * 
     * @return
     *   HaptiMap.SUCCESS if a valid current location was successfully stored in the
     *   array location. HaptiMap.FAILURE if an invalid sensor ID was given, if the
     *   sensor does not support retrieving a location in WGS84 co-ordinates, if 
     *   the sensor was currently inactive, or if it cannot currently offer
     *   a valid accurate location reading.
     */
    public native int LocationSensorGetLocationWGS84(int id, double[] location, int[] is_3d);

    public native int SensorInquire(SENSOR_TYPE type, int[] count);
    public native int SensorGetId(SENSOR_TYPE type, int n, int[] id);
    public native int SensorGetAttribute(int id, ATTRIBUTE att, int[] val);
    public native int SensorGetAttributeMultiple(int id, ATTRIBUTE att, int[] vals);
    public native int SensorGetAttributeString(int id, ATTRIBUTE att, StringBuilder val);
    public native int SensorInitialise(int id);
    public native int SensorUninitialise(int id);
    public native int SensorDefineCallback(int id, EVENT_TYPE event, HaptiMapCallbackType cb_interface);
    public native int SensorCancelCallback(int id, EVENT_TYPE event);

    /** Class implementing an Android location listener used by the toolkit core to
     *  receive notifications from the Android location sensor API. This class is never
     *  used from Java and is instantiated only from JNI code in the toolkit core. */
    @SuppressWarnings("unused")
    private static class HaptiMapLocationListener implements LocationListener {
        public native void onLocationChanged(Location location);
        public native void onStatusChanged(String provider, int status, Bundle extras);
        public native void onProviderDisabled(String provider);
        public native void onProviderEnabled(String provider);
        /** Pointer to toolkit Android device object */
        private long adev;
        /** Index of this location sensor within the device */
        private int id_device;
    }

	 /**
		* Class for Android sensor listener used by the interal toolkit core
		*/
	 @SuppressWarnings("unused")
	 private static class HaptiMapSensorListener implements SensorEventListener {
       public native void onAccuracyChanged(Sensor sensor, int accuracy);
		 public native void onSensorChanged(SensorEvent event);
	 }

    /** Class that extends the Android GLSurfaceView for use by the toolkit visual
     *  display API, which handles an OpenGL display using a platform-independent
     *  API. Note that this is not necessarily needed in order to use OpenGL mantle
     *  functionality in the toolkit; the GLSurfaceView may be set up independently
     *  by the application. This class is never used from Java and is instantiated only
     *  from JNI code in the toolkit core. */
    /* This does nothing more than a GLSurfaceView at the minute, but will be
     * extended with native methods to handle touch events and maybe more. */
    @SuppressWarnings("unused")
    private static class HaptiMapGLView extends GLSurfaceView {
        public HaptiMapGLView(Context ctx) {
                super(ctx);
        }
    }

    /** Class that implements an Android GL Renderer in a manner compatible with the 
     *  toolkit visual display API. This class is never used from Java and is instantiated
     *  only from JNI code in the toolkit core. Note also that it is not necessary 
     *  to use the toolkit visual display API in order to use OpenGL mantle
     *  functionality in the toolkit. */
    @SuppressWarnings("unused")
    private static class HaptiMapGLRenderer implements GLSurfaceView.Renderer {
        private long params; /**< Pointer to toolkit render parameters */
        private int width, height; /**< Current width and height of graphics display */

        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            init_callback();
        }
        public void onSurfaceChanged(GL10 gl, int w, int h) {
            /** This method only stores the new width and height, which will
             *  be passed to the native render method when it is called. */
            width = w;
            height = h;
        }
        public void onDrawFrame(GL10 gl) {
            render_callback(width, height);
        }

        private native void init_callback();
        private native void render_callback(int w, int h);
    }
}
